﻿

#include "stdafx.h"
#include "resource.h"
#include "CManageEx.h"
using namespace std;

/** 
 * CManage includes follwing functions: 
		1.CManageEx();
		2. Insert rectangle
		3. Insert Circle
		4. Insert Triangle
		5. Insert Line
		6. Insert Round Rectangle
		7. DeleteShape 1 shape at a particular index
		8. Delete all selected shapes
		9. AddSelectedShape
		10. ResetSelectedShape
		11. Get 1 Shape
		12. Show all shapes
		13. CheckInShape. Return TRUE if 1 shape was selected
		14. Check Inshape (2 args). Quét chon.
		15. DrawSelected.  Draw small rectangle o các dau mut shape duoc chon
		16. DrawSelecting. Draw hinh chu nhat net dut de chon shape
		17. Move
		18. SelectShape. 
		19. Draw shape
		20. CreateNewGraphic
		21. SaveGraphic(HWND, LPWSTR);
		22. OpenGraphic
		23. CheckResizingMode. return position cua dau mut duoc chon de resize
		24. Resize 1 selected shape
		25. Curmaxmin. Update current boudary of shapes
 */

/* Constructor */
CManageEx::CManageEx()
{
	quantity = 0;
	allowMoving = false;
	isMoving = false;
	isSeleting = false;
	isDrawing = false;
	allowTyping = false;
	allowResizing = false;
	isResizing = false;
	maxtop = _BOTTOMWINDOW_;
	minbottom = _TOPWINDOW_;
	minleft = _RIGHTWINDOW_;
	maxright = _LEFTWINDOW_;
	position = _LEFTTOP_;
	selectingQuantity = 0;
	numbertextshape = 0;
}


/* Insert rectangle */
void CManageEx::InsertShape(CRectangleEx rect, int index)
{	
	listShape.insert(listShape.begin() + index, new CRectangleEx(rect));
	quantity ++ ;	
}

/* Insert circle */
void CManageEx::InsertShape(CCircleEX cir, int index)
{
	listShape.insert(listShape.begin() + index, new CCircleEX(cir));
	quantity ++ ;
}

/* Insert triangle */
void CManageEx::InsertShape(CTriangleEx tri, int index)
{	
	listShape.insert(listShape.begin() + index, new CTriangleEx(tri));
	quantity ++ ;	
}

/* Insert line */
void CManageEx::InsertShape(CLineEx line, int index)
{	
	listShape.insert(listShape.begin() + index, new CLineEx(line));
	quantity ++ ;	
}

/* Insert Round rect*/ 
void CManageEx::InsertShape(CRoundRectangleEx roundrect, int index)
{	
	listShape.insert(listShape.begin() + index, new CRoundRectangleEx(roundrect));
	quantity ++ ;	
}

/* Insert Text*/ 
void CManageEx::InsertShape(CTextEx text, int index)
{	
	listShape.insert(listShape.begin() + index, new CTextEx(text));
	quantity ++ ;	
}

/* Delete 1 Shape at particular index */
void CManageEx::DeleteShape(int index)
{
	if (index >= 0 && quantity > 0)
	{
		listShape.erase(listShape.begin() + index);
		quantity -- ;
	}
}

/* DeleteShape all selected shapes */
void CManageEx::DeleteShape()
{
	int i; 

	for (i = 0; i < selectingQuantity; i++)
	{
		DeleteShape(selectingPosition.at(i));
	}

	ResetSelectedShape();
	allowMoving = false;
	isMoving = false;
	isDrawing = false;
}

/* Add Selected Shape */
void CManageEx::AddSelectedShape(int index)
{
	selectingPosition.insert(selectingPosition.begin() + selectingQuantity, index);
	selectingQuantity ++ ;
}

/* Reset selected shape */
void CManageEx::ResetSelectedShape()
{
	selectingQuantity = 0;
	selectingPosition.clear();
}

/* GetShape at particular index */
CShapeEx* CManageEx::GetShape(int index)
{
	return listShape.at(index);
}

/* ShowAll */
void CManageEx::ShowAll(HDC hdc)
{
	int i = 0;
	int j = 0;
	int _pattern;

	while (i < quantity)
	{	
		listShape.at(i)->GetInfor(_PATTERN_, _pattern);
		if (_TEXT_ == _pattern)
		{
			listShape.at(i)->View(hdc, buffer);
			j ++;
		}
		else 
		{
			listShape.at(i)->View(hdc);
		}
		i ++;
		
	}		
}

/* CheckInShape : return true neu chon dung */
bool CManageEx::CheckInShape(POINT p)
{
	int i;
	
	if (selectingQuantity != 0)
	{
		for (i = 0; i < selectingQuantity; i++)
		{
			if (listShape.at(selectingPosition.at(i))->IsInShape(p))
				return true;
		}
	}
	else 
	{		
		ResetSelectedShape();
		for (i = quantity - 1; i >= 0; i--)
		{			
			if (listShape.at(i)->IsInShape(p))
			{
				AddSelectedShape(i);
				return true;
			}		
		}
	}
	
	return false;	
}

/* CheckInShape : tim xem quet duoc bao nhieu hinh va dua vao selectingPosition */
void CManageEx::CheckInShape(POINT point1, POINT point2)
{
	int i;

	ResetSelectedShape();
	for (i = quantity - 1; i >= 0; i--)
	{		
		if (listShape.at(i)->IsInShape(point1, point2))
		{
			AddSelectedShape(i);
		}
	}
}

/* DrawSelected : Draw 4 small rectangle to show what selected shape */
void CManageEx::DrawSelected(HDC hdc)
{
	int i;
	int _left;
	int _top;
	int _right;
	int _bottom;
	int _pattern;
	HBRUSH hBrush, hOldBrush;

	hBrush = CreateHatchBrush(HS_FDIAGONAL, RGB(10,10,10));
	hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);		
		
	for (i = 0; i < selectingQuantity; i++)
	{
		listShape.at(selectingPosition.at(i))->GetInfor(_left, _top, _right, _bottom);
		listShape.at(selectingPosition.at(i))->GetInfor(_PATTERN_,_pattern);
		switch (_pattern)
		{
			case _RECTANGLE_:

			case _ROUNDRECTANGLE_:

			case _CIRCLE_:
				Rectangle(hdc, _right - 5, _top - 5, _right + 5, _top + 5);					
				Rectangle(hdc, _left - 5, _bottom - 5, _left + 5, _bottom + 5);					
		
			case _LINE_:
				Rectangle(hdc, _left - 5, _top - 5, _left + 5, _top + 5);						
				Rectangle(hdc, _right - 5, _bottom - 5, _right + 5, _bottom + 5);							
				break;

			case _TRIANGLE_:
				Rectangle(hdc, (_left + _right)/2 - 5, _top - 5, (_left + _right)/2 + 5, _top + 5);						
				Rectangle(hdc, _right - 5, _bottom - 5, _right + 5, _bottom + 5);					
				Rectangle(hdc, _left - 5, _bottom - 5, _left + 5, _bottom + 5);	
				break;
			
			default:
				break;	//do nothing
		}	
	}

	DeleteObject(hBrush);
	SelectObject(hdc, hOldBrush);
}

/* Draw 1 rectangle with dash style to show what shape will be selected */
void CManageEx::DrawSelecting(HDC hdc)
{	
	selectRect.SetInfor(point1.x, point1.y, oldPoint2.x, oldPoint2.y, false, 
						 1, PS_DASH, RGB(255, 255, 255), RGB(255, 255, 255), _RECTANGLE_);
	selectRect.View(hdc);
	selectRect.SetInfor(point1.x, point1.y, point2.x, point2.y, false, 
						 1, PS_DASH, RGB(255, 255, 255), RGB(0, 0, 0), _RECTANGLE_);
	selectRect.View(hdc);
}

/* Move */
void CManageEx::Move(int dx, int dy)
{
	int i;
	
	for (i = 0; i < selectingQuantity; i++)
	{
		listShape.at(selectingPosition.at(i))->Move(dx, dy);
	}
}

/* Select Shape */
void CManageEx::SelectShape(HDC hdc, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{	
	
	RECT rect;

	GetClientRect(hWnd, &rect);

	switch(message)
	{
		case WM_LBUTTONUP:

			// lay toa do chuot lúc buông chuột
			point2.x = LOWORD(lParam);
			point2.y = HIWORD(lParam);

			//Buông chuột thì bỏ chê độ move, nhưng vẫn còn chế độ chọn nếu vừa move xong
			isSeleting = false;
			if (isMoving || isResizing)
			{
				// Draw select
				DrawSelected(hdc);
				isMoving = false;			
				isResizing = false;
				return;
			}

			// If isMoving == FALSE 
			if ((point1.x == point2.x) && (point1.y == point2.y)) // LButtonDown và Up trùng vị trí
			{
				// kiểm tra chọn trong shape 
				if (!CheckInShape(point1)) //1. chon sai
				{			
					allowMoving = false;
					allowResizing = false;
					InvalidateRect(hWnd, NULL, TRUE); // reset lai window
					return;
				}
				else if (1 == selectingQuantity)// 2. chọn đúng 1 shape
				{
					allowMoving = true; 
					allowResizing = true;
					ShowAll(hdc);

					// draw select de phan biet voi shape khong duoc chon
					DrawSelected(hdc);
				}		
			}
			else 
			{
				CheckInShape(point1, point2);

				//1. chon sai
				if (0 ==selectingQuantity) 
				{					
					Rectangle(hdc, rect.left, rect.top + 30, rect.right, rect.bottom - 30);
					ShowAll(hdc);
					allowMoving = false;
					return;
				}
				else // 2. chọn đúng
				{
					allowMoving = true; 
					ShowAll(hdc);

					// draw select de phan biet
					DrawSelected(hdc);
				}
			}
			break;

		case WM_LBUTTONDOWN:
			
			point1.x = LOWORD(lParam);
			point1.y = HIWORD(lParam);

			if (allowMoving)
			{
				int i;
				for (i = 0; i < selectingQuantity; i++)
				{
					if (!CheckInShape(point1))
					{
						position = CheckResizingMode(point1);
						if (position != -1)
						{ 
							isResizing = true;
							return;
						}						
						allowMoving = false;
						allowResizing = false;
						ResetSelectedShape();
						InvalidateRect(hWnd, NULL, TRUE);
						return;
					}
				}
				isMoving = true;			
			}
			isSeleting = true;
			break;

		case WM_MOUSEMOVE:
			oldPoint2 = point2;
			point2.x = LOWORD(lParam);
			point2.y = HIWORD(lParam);

			if (isMoving)
			{				
				int dx;
				int dy;
				dx = point2.x - point1.x;
				dy = point2.y - point1.y;
				point1 = point2;	
				CurMaxMin();
				if (_TOPWINDOW_ > maxtop + dy || _BOTTOMWINDOW_  < minbottom + dy)
					dy = 0;
				if (_LEFTWINDOW_ > minleft + dx || _RIGHTWINDOW_ < maxright + dx)
					dx = 0;
				Move(dx, dy);				
				Rectangle(hdc, rect.left, rect.top + 30, rect.right, rect.bottom - 30);
				ShowAll(hdc);
				break;
			}
			else if (isSeleting)
			{				
				DrawSelecting(hdc);	
				ShowAll(hdc);
			}
			else if (isResizing)
			{
				CurMaxMin();
				if (_TOPWINDOW_ > maxtop || _BOTTOMWINDOW_  < minbottom)
					point2.y = oldPoint2.y;
				if (_LEFTWINDOW_ > minleft || _RIGHTWINDOW_ < maxright)
					point2.x = oldPoint2.x;
				Resize(point2.x, point2.y, position);
				Rectangle(hdc, rect.left, rect.top + 30, rect.right, rect.bottom - 30);
				ShowAll(hdc);
			}
			break; 

		default:
				break;	//do nothing
	}
	ReleaseDC(hWnd, hdc);		
}

/* Draw Shape */
void CManageEx::DrawShape(HDC hdc, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, ShapeAttribute SAttribute)
{	
	CRectangleEx rect;
	CCircleEX cir;
	CTriangleEx tri;
	CLineEx line;
	CRoundRectangleEx roundrect;
	RECT r;

	hdc = GetDC(hWnd);
	GetClientRect(hWnd, &r);

	ResetSelectedShape();
	allowMoving = false;
	isMoving = false;
	isSeleting = false;
	
	switch(message)
	{
		case WM_LBUTTONUP:
			point2.x = LOWORD(lParam);
			point2.y = HIWORD(lParam);			
			isDrawing = false;

			if ((point1.x == point2.x) && (point1.y == point2.y))
			{
				DeleteShape(quantity - 1);
			}			
			break;

		case WM_LBUTTONDOWN:			
			point1.x = LOWORD(lParam);
			point1.y = HIWORD(lParam);
			isDrawing = true;

			switch (SAttribute.pattern)
			{
				case _RECTANGLE_:
					rect.SetInfor(_PATTERN_, SAttribute.pattern);
					rect.SetInfor(_PENWIDTH_, SAttribute.penWidth);
					rect.SetInfor(_PENCOLOR_, SAttribute.penColor);
					rect.SetInfor(_BRUSHCOLOR_, SAttribute.brushColor);
					rect.SetInfor(_PENSTYLE_, SAttribute.penStyle);
					rect.SetInfor(SAttribute.filled);
					InsertShape(rect, quantity);
					break;

				case _CIRCLE_:
					cir.SetInfor(_PATTERN_, SAttribute.pattern);
					cir.SetInfor(_PENWIDTH_, SAttribute.penWidth);
					cir.SetInfor(_PENCOLOR_, SAttribute.penColor);
					cir.SetInfor(_BRUSHCOLOR_, SAttribute.brushColor);
					cir.SetInfor(_PENSTYLE_, SAttribute.penStyle);
					cir.SetInfor(SAttribute.filled);
					InsertShape(cir, quantity);
					break;

				case _TRIANGLE_:
					tri.SetInfor(_PATTERN_, SAttribute.pattern);
					tri.SetInfor(_PENWIDTH_, SAttribute.penWidth);
					tri.SetInfor(_PENCOLOR_, SAttribute.penColor);
					tri.SetInfor(_BRUSHCOLOR_, SAttribute.brushColor);
					tri.SetInfor(_PENSTYLE_, SAttribute.penStyle);
					tri.SetInfor(SAttribute.filled);			
					InsertShape(tri, quantity);
					break;

				case _LINE_:
					line.SetInfor(_PATTERN_, SAttribute.pattern);
					line.SetInfor(_PENWIDTH_, SAttribute.penWidth);
					line.SetInfor(_PENCOLOR_, SAttribute.penColor);
					line.SetInfor(_BRUSHCOLOR_, SAttribute.brushColor);
					line.SetInfor(_PENSTYLE_, SAttribute.penStyle);
					line.SetInfor(SAttribute.filled);		
					InsertShape(line, quantity);
					break;

				case _ROUNDRECTANGLE_:
					roundrect.SetInfor(_PATTERN_, SAttribute.pattern);
					roundrect.SetInfor(_PENWIDTH_, SAttribute.penWidth);
					roundrect.SetInfor(_PENCOLOR_, SAttribute.penColor);
					roundrect.SetInfor(_BRUSHCOLOR_, SAttribute.brushColor);
					roundrect.SetInfor(_PENSTYLE_, SAttribute.penStyle);
					roundrect.SetInfor(SAttribute.filled);			
					InsertShape(roundrect, quantity);
					break;
				
				default:
					break;	//do nothing
			}
			break;

		case WM_MOUSEMOVE:
			point2.x = LOWORD(lParam);
			point2.y = HIWORD(lParam);

			if (isDrawing)
			{		
				Rectangle(hdc, r.left, r.top + 30, r.right, r.bottom);			
				listShape.at(quantity - 1)->SetInfor(point1.x, point1.y, point2.x, point2.y);

				//draw to screen
				ShowAll(hdc);
				ReleaseDC(hWnd, hdc);			
			}

		default:
				break;	//do nothing
	}			
}

/* Draw Text */

void CManageEx::DrawTextShape(HDC hdc, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
			  ShapeAttribute SAttribute)
{	

	CTextEx text;
	RECT r;

	hdc = GetDC(hWnd);
	GetClientRect(hWnd, &r);

	switch(message)
	{
		case WM_LBUTTONUP:
			point2.x = LOWORD(lParam);
			point2.y = HIWORD(lParam);			
			isDrawing = false;
			
			if ((point1.x == point2.x) && (point1.y == point2.y))
			{
				if (isTyping)
				{
					if (! listShape.at(quantity-1)->IsInShape(point2)) //point to outer shape
					{
						// destroy variables used for drawing text
						UnregisterHotKey ( hWnd, 0xAAAA );
						delete tAttribute;

						//destroy caret
						HideCaret (hWnd);
						DestroyCaret ();

						allowTyping = false;
						isTyping = false;

						// set pen width = 1 to indicate that we must erase text-boundary rectangle
						listShape.at(quantity - 1)->SetInfor(_PENWIDTH_, 1);

						////textshape.push_back( buffer );

						InvalidateRect(hWnd, NULL, TRUE);
					}
					else // point to inner shape
					{
						ShowCaret (hWnd);
						// Continue typing
					}
				}
				else 
				{
					DeleteShape(quantity - 1);
				}	
				return;
			}			

			else if (allowTyping)
			{
				isTyping = TRUE;

				// display created caret
				ShowCaret (hWnd);

				break;
			}
			break;

		case WM_LBUTTONDOWN:			
			point1.x = LOWORD(lParam);
			point1.y = HIWORD(lParam);
			isDrawing = true;
			
			// SET attribute
			text.SetInfor(_PATTERN_, SAttribute.pattern);
			text.SetInfor(_PENWIDTH_, 3000); //flag to indicate that we must draw text-boundary rectangle
			text.SetInfor(_PENCOLOR_, SAttribute.penColor);
			text.SetInfor(_BRUSHCOLOR_, SAttribute.brushColor);
			text.SetInfor(SAttribute.filled);
			InsertShape(text, quantity);
			allowTyping = TRUE;

			// Get current font  
			tAttribute = new TextAttribute;
			TEXTMETRIC tm; //Cấu trúc metriccủavănbản
			hdc = GetDC (hWnd);
			GetTextMetrics (hdc, &tm);
			ReleaseDC (hWnd, hdc);
			tAttribute->dwCharX = tm.tmAveCharWidth;
			tAttribute->dwCharY = tm.tmHeight;

			// Create and display caret 
			CreateCaret (hWnd, (HBITMAP) 1, 0, tAttribute->dwCharY);
			tAttribute->nCaretPosX = 0 /* point1.x*/;
			tAttribute->nCaretPosY =0 /* point1.y*/;

			// set default values
			tAttribute->nCharWidth = 0;
			tAttribute->nCurChar = 0; 
			SetCaretPos (tAttribute->nCaretPosX, tAttribute->nCaretPosY);
			tAttribute->count = 0;

			break;

		case WM_MOUSEMOVE:
			point2.x = LOWORD(lParam);
			point2.y = HIWORD(lParam);

			if (isDrawing)
			{		
				Rectangle(hdc, r.left, r.top + 30, r.right, r.bottom - 30);			
				listShape.at(quantity - 1)->SetInfor(point1.x, point1.y, point2.x, point2.y);

				//draw to screen
				ShowAll(hdc);
			}
			break;
			
		case WM_CHAR:
			int i;
			int j;

			if (isTyping)
			{
				switch (wParam)
				{ 
					case 0x08: // Backspace
					case 0x0A: // Linefeed
					case 0x1B: // Escape
						MessageBeep((UINT) 0);
						return;
					case 0x09: // tab

						// Chuyển phím tab thành 4 kítự trắng liêntục nhau 
						for (i = 0; i < 4; i ++)
							SendMessage (hWnd, WM_CHAR, 0x20, 0);

						return;
					case 0x0D: // Xuống dòng

						// Lưu kí tự xuống dòng và tạo dòng mới đưa caret xuống vị trí mới 
						buffer [tAttribute->count - 1] = '\n';
						tAttribute->count ++;
						tAttribute->nCaretPosX = 0;
						tAttribute->nCaretPosY += 1;
						tAttribute->nCurChar = tAttribute->count;

						break;
					default: //Xử lý những kítự có thể hiển thị được 
						switch (wParam)
						{
						case 'q':
							buffer [tAttribute->count - 1] = 'q';
							break;
						}
						
						tAttribute->count ++;
						HideCaret (hWnd);

						// Lấybề dàycủa kítự và xuất ra 
						hdc = GetDC (hWnd);
						GetCharWidth32 (hdc,(UINT) wParam, (UINT)wParam, 
										& tAttribute->nCharWidth);
						TextOutA(hdc, tAttribute->nCaretPosX, tAttribute->nCaretPosY * tAttribute->dwCharY,
								&buffer [tAttribute->count - 1] , 1);
						
						ReleaseDC (hWnd, hdc);

						// Tính lại vị trí ngang của caret. Nếu vị trí này tới cuối dòng thì
						// chèn thêm kí tự xuống dòng và di chuyển caret đến dòng mới  
						tAttribute->nCaretPosX += tAttribute->nCharWidth;
						if ((DWORD) tAttribute->nCaretPosX > tAttribute->dwLineLen)
						{ 
							tAttribute->nCaretPosX = 0;
							buffer [tAttribute->count - 1] = (CHAR)0x0D;
							tAttribute->count ++;
							++ tAttribute->nCaretPosY;
						} 
						tAttribute->nCurChar = tAttribute->count;
						ShowCaret (hWnd);

						break;
				} //end switch

				SetCaretPos (tAttribute->nCaretPosX, tAttribute->nCaretPosY * tAttribute->dwCharY);
			}// endif
			break;
			/*
		case WM_KEYDOWN:
			if (isTyping)
			{
				switch (wParam)
				{ 
					case VK_LEFT: // LEFT arrow

						// Caret di chuyển qua trái và chỉ đến đầu dòng 
						if (tAttribute->nCaretPosX > 0)
						{ 
							HideCaret (hWnd);

							// Tính toánlạivị trícủa caret khi qua trái 
							-- tAttribute->nCurChar;
							hdc = GetDC (hWnd);
							GetCharWidth32 (hdc, tAttribute->ch, tAttribute->ch, & tAttribute->nCharWidth);
							ReleaseDC (hWnd, hdc); 	
							tAttribute->nCaretPosX=max(tAttribute->nCaretPosX - tAttribute->nCharWidth,0);
							ShowCaret (hWnd);

						}  // end if (nCaretPosX > 0)

						break;
					case VK_RIGHT: // RIGHT arrow 

						// Di chuyển caret sang phải 
						if (tAttribute->nCurChar < tAttribute->count)
						{ 
							HideCaret (hWnd);

							// Tính toánlạivị trícủa caret khi sang phải 
							-- tAttribute->nCurChar;

							if ('\n' == textshape.at(tAttribute->count))
							{ 
								tAttribute->nCaretPosX = 0;
								tAttribute->nCaretPosY ++;
							} 

							//Nếu kí tự không phải là enter thì kiểm tra xem phím shift có được
							//nhấn hay không. Nếu có nhấn thì đổi màu và xuất ra màn hình.  
							else
							{ 
								hdc = GetDC (hWnd);
								tAttribute->nVirtKey = GetKeyState (VK_SHIFT);
								if (tAttribute->nVirtKey & SHIFTED)
								{ 
									tAttribute->crPrevText=SetTextColor(hdc,RGB (255, 255, 255));
									tAttribute->crPrevBk= SetBkColor(hdc,RGB(0,0,0));
									TextOutA(hdc, tAttribute->nCaretPosX, 
												tAttribute->nCaretPosY * tAttribute->dwCharY, &tAttribute->ch, 1);
									SetTextColor (hdc, tAttribute->crPrevText);
									SetBkColor (hdc, tAttribute->crPrevBk);
								} 
								GetCharWidth32(hdc, tAttribute->ch, tAttribute->ch,& tAttribute->nCharWidth);
								ReleaseDC (hWnd, hdc);
								tAttribute->nCaretPosX = tAttribute->nCaretPosX + tAttribute->nCharWidth;
							} 
							tAttribute->nCurChar ++;
							ShowCaret (hWnd);
							break;
						} //end if (nCurChar < count)
						break;
				
					case VK_UP: // Phímmũi tên lên
					case VK_DOWN: // Phímmũi tên xuống
						MessageBeep ((UINT) 0);
						return;

					case VK_HOME: // Phím home

						// Thiết lập vị trí của caret ở dòng đầu tiên 
						tAttribute->nCaretPosX = tAttribute->nCaretPosY = 0;
						tAttribute->nCurChar = 0;

						break;
					case VK_END: // Phím end

						// Di chuyển về cuối văn bản và lưu vị trí của kí tự xuống dòng cuối 
						for (i=0; i < tAttribute->count; i++)
						{ 
							if ('\n' == textshape.at(i))
							{ 
								//tAttribute->cCR ++;
								//tAttribute->nCRIndex = i + 1;
							} 
						} 
						

						// Chéptấtcả các kítựtừ kítự xuống dòng cuối đến kítự hiện thờivừa nhậptừ bàn phím vàobộ nhớ đệm. 
						for (i = tAttribute->nCRIndex, j = 0; i < tAttribute->count; i++, j++)
							tAttribute->szBuf [j] = tAttribute->pchInputBuf [i];
						tAttribute->szBuf [j] = TEXT ('\0');

						// Tínhvị trídọccủa caret 
						hdc = GetDC (hWnd);
						GetTextExtentPoint32(hdc, tAttribute->szBuf, lstrlen(tAttribute->szBuf), & tAttribute->sz);
						tAttribute->nCaretPosX = tAttribute->sz.cx;
						ReleaseDC (hWnd, hdc);
						tAttribute->nCurChar = tAttribute->count;
						break;
					default:
						break;
				} // end switch

				SetCaretPos(tAttribute->nCaretPosX, tAttribute->nCaretPosY * tAttribute->dwCharY);
				break;			
			
			}
			*/
		default:
			break;	//do nothing
			
	}			
}

/* Create New Graphic */
void CManageEx::CreateNewGraphic()
{
	listShape.clear();
	quantity = 0;
}

/* Save graphic */
bool CManageEx::SaveGraphic(HWND hWnd,TCHAR* address)
{
	fstream fShapeList;
	char fAddress[MAX_PATH];
	size_t t;
	int i;

	wcstombs_s(&t, fAddress, address, 100);
	
	fShapeList.open(fAddress /*"thanhtamtam.dtl"*/, ios::out | ios::app);
	
	if (!fShapeList.is_open())
		return FALSE;

	for (i = 0; i < quantity; i++)
	{
		fShapeList.write((char*)listShape.at(i), sizeof(CShapeEx));
	}
	fShapeList.close();
	return TRUE;
}

/* Open graphic */
bool CManageEx::OpenGraphic(HWND hWnd, TCHAR* address)
{	
	fstream fShapeList;
	int _left;
	int _top;
	int _right;
	int _bottom;
	bool _filled;
	int _penWidth;
	int _penStyle;
	int _pattern;	
	COLORREF _brushColor;
	COLORREF _penColor;
	char fAddress[MAX_PATH];
	size_t t;
	CShapeEx* shape = new CShapeEx;
	CRectangleEx rect;
	CCircleEX cir;
	CRoundRectangleEx roundrect;
	CTriangleEx tri;
	CLineEx line;

	wcstombs_s (&t, fAddress, address, 100);
	fShapeList.open (fAddress, ios::in | ios::binary);

	if (!fShapeList.is_open())
	{
		MessageBoxA(hWnd, fAddress, "fdefe", 0);
		return FALSE;
	}

	while (!fShapeList.eof())
	{
		fShapeList.read(reinterpret_cast <char*> (shape), sizeof(CShapeEx));
		shape->GetInfor(_left, _top, _right, _bottom, _filled,
						_penWidth, _penStyle, _brushColor, _penColor,
						_pattern);
		switch (_pattern)		
		{
			case _RECTANGLE_:
				rect.SetInfor(_left, _top, _right, _bottom, _filled,
								_penWidth, _penStyle, _brushColor, _penColor, 
								_pattern);
				InsertShape(rect, quantity);			
				break;

			case _CIRCLE_:
				cir.SetInfor(_left, _top, _right, _bottom, _filled,
								_penWidth, _penStyle, _brushColor, _penColor,
								_pattern);
				InsertShape(cir, quantity);
				break;

			case _LINE_:
				line.SetInfor(_left, _top, _right, _bottom, _filled,
								_penWidth, _penStyle, _brushColor, _penColor,
								_pattern);
				InsertShape(line, quantity);
				break;

			case _ROUNDRECTANGLE_:
				roundrect.SetInfor(_left, _top, _right, _bottom, _filled,
									_penWidth, _penStyle, _brushColor, _penColor,
									_pattern);
				InsertShape(roundrect, quantity);
				break;

			case _TRIANGLE_:
				tri.SetInfor(_left, _top, _right, _bottom, _filled,
									_penWidth, _penStyle, _brushColor, _penColor,
									_pattern);
				InsertShape(tri, quantity);
				break;
			//case _TEXT_:

			default:
				break;	//do nothing
		}
	}
	fShapeList.close() ;
	return true;
}

/* Check resize mode. Return position */
int CManageEx::CheckResizingMode(POINT p)
{

	return listShape.at(selectingPosition.at(selectingQuantity - 1))->isResizing(p);
}

/* Resize selected shape */
void CManageEx::Resize(int newx, int newy, int position)
{
	listShape.at(selectingPosition.at(0))->Resize(newx, newy, position);
}

/* Curmaxmin() */
void CManageEx::CurMaxMin()
{
	int i;
	int _top;
	int _left;
	int _right;
	int _bottom;

	if (0 == selectingQuantity)
		return;

	listShape.at(selectingPosition.at(0))->GetInfor(_left, _top, _right, _bottom);
	maxtop = _top;
	minbottom = _bottom;
	minleft = _left;
	maxright = _right;
	for (i = 1; i < selectingQuantity; i++)
	{
		listShape.at(selectingPosition.at(i))->GetInfor(_left, _top, _right, _bottom);
		if (_top < maxtop)
			maxtop = _top;
		if (_bottom > minbottom)
			minbottom = _bottom;
		if (_left < minleft)
			minleft = _left;
		if (_bottom > maxright)
			maxright = _right;
	}
}
